﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Common.Models;

namespace SGH
{
    /// <summary>
    /// 圆形件下料顺序分组启发式算法+递推算法
    /// </summary>
    public class Program
    {
        private static List<Output> _outputs;
        Output output = new Output();
        private Input _input;
        public void Start(Input input, int patternType, ref List<Output> outputs,object paras)
        {
            #region 参数设置
            _input = input;
            _outputs = outputs;
            Constant.sheetLength = (int)input.Length;
            Constant.sheetWidth = (int)input.Width;
            Constant.blankTypeNum = input.Num;

            int n = Constant.blankTypeNum;

            Constant.diameter = new int[n];
            Constant.allowance = new int[n];
            Constant.demand = new int[n];


            for (int i = 0; i < n; i++)
            {
                Constant.diameter[i] = (int)input.Diameter[i];
                Constant.demand[i] = input.Demand[i];
                Constant.allowance[i] = 0;
            }


            Constant.squer = input.Squer;//记录毛坯的总面积
            #endregion

            #region 程序执行

            DateTime dt1 = DateTime.Now;
            if (patternType == 0)
            {
                Constant.IsControl = false;
                doTestForOne();
            }
            else if (patternType == 1)
            {
                doTest();
            }
            else if (patternType == 2)
            {
                doSGH();
            }
            else if (patternType == 3)
            {
                //设置为余料控制
                Constant.IsControl = true;
                Constant.IsControl = true;
                var paraStr = paras as string;
               var paraList= paraStr.Split('，', ',');
                Constant.OffcutTypeNumLimit = int.Parse(paraList[1]);
                Constant.OffcutWidthLimit = int.Parse(paraList[0]);
                doTestForOne();
            }
            DateTime dt2 = DateTime.Now;
            Constant.dt = dt2 - dt1;

            Console.WriteLine("计算完成，使用了这么多时间：" + Constant.dt);
            #endregion

        }

        public void doSGH()
        {
            SGH sgh = new SGH();
            SGH.solve();
        }

        public void doTestForOne()
        {
            //Test test = new Test(5, 4.8); 
            Test test = new Test(5, 4.22);
            var pattern = test.dopattern(1);
            print(pattern);
            //Console.WriteLine("消耗板材张数=" + Test.sheetNum + "；排样方式种类数=" + Test.patternNum + "；材料利用率=" + Test.rate);
        }

        public void doTest()
        {
            double maxRate = 0.0;
            double maxP = 0;
            int maxDelta = 0;
            double maxBeta = 0;
            int maxPatternNum = 0;
            int maxSheetNum = 0;
            List<List<int[]>> maxPattern = new List<List<int[]>>();
            var tasks = new List<Task>();
            for (int i = 0; i < 10; i++)
            {
                Constant.p = 1.02 + 0.02 * i;
                for (int j = 2; j < 6; j++)
                    for (double x = 0.5; x < 6.5; x += 0.3)
                    {

                        var task = Task.Run(() =>
                          {
                              Test test = new Test(j, x);
                              Constant.pattern = test.dopattern(0);
                              lock (test)
                              {
                                  if (Test.rate > maxRate)
                                  {
                                      maxPattern = Constant.pattern;
                                      maxRate = Test.rate;
                                      maxP = Constant.p;
                                      maxDelta = j;
                                      maxBeta = x;
                                      maxPatternNum = Test.patternNum;
                                      maxSheetNum = Test.sheetNum;
                                  }
                              }
                          });
                        tasks.Add(task);
                    }
            }
            Task.WaitAll(tasks.ToArray());
            Test.rate = maxRate;
            Constant.p = maxP;
            Test.patternNum = maxPatternNum;
            Test.sheetNum = maxSheetNum;
            print(maxPattern);
        }
        /// <summary>
        /// 输出结果
        /// </summary>
        /// <param name="pattern">计算结果</param>
        public void print(List<List<int[]>> pattern)
        {
            output.Length = _input.Length;
            output.Width = _input.Width;
            output.Num = _input.Num;
            //用会静态类Constant的毛坯直径，因为已经被调换顺序
            output.Diameter =Array.ConvertAll(Constant.diameter, o => (double)o);
            output.Demand = Constant.demand;
          
            int n = pattern.Count;
            output.PlateRemark = new List<string>(n);
            //每种排样消耗板材数量
            var plateNum = new List<int>();
            for (int i = 0; i < n; i++)
            {
                var m = pattern[i].Count - 1;
                plateNum.Add(pattern[i][m][0]);
            }
            output.PlateNum = plateNum.ToArray();

            //每种排样各毛坯使用数
            output.DiaNum = new List<int[]>();
            for (int i = 0; i < n; i++)
            {
                var diaNum = new int[_input.Num];
                for (int j = 0; j < pattern[i].Count - 1; j++)
                {
                    if (pattern[i][j][2]==2)
                        continue;
                    var id = pattern[i][j][0];
                    var num = pattern[i][j][4];
                    diaNum[id] += num;
                }
                output.DiaNum.Add(diaNum);
            }

            #region 所有排样方式

            output.Plates = new List<List<List<int[]>>>();

            //每个排样方式
            for (int i = 0; i < n; i++)
            {
                //一种排样方式
                output.Plate = new List<List<int[]>>();
                //一个排样方式中所有椭圆的数据
                var ellipses = new List<int[]>();
                //一个排样方式中所有直线的数据
                var lines = new List<int[]>();
                //一个排样方式中所有矩形的数据
                output.Rectangles = new List<int[]>();
                //排样下的说明
                output.PlateRemark.Add("");

                int[] ret = new int[] { 1, 0, 0,(int) output.Length , (int)output.Width, 1, 1 };
                output.Rectangles.Add(ret);
                double x = 0, y = 0;//初始化矩形坐标
                List<int[]> onePattern = pattern[i];

                int m = onePattern.Count - 1;
                Constant.sheetLength = (int)output.Length;
                //一个方式中的一条条带
                for (int j = 0; j < m; j++)
                {
                    PrintStripe(onePattern[j],ref x, ref y, ref ellipses, ref lines);
                }
                output.Ellipses = ellipses;
                output.Lines = lines;

                output.Plate.Add(output.Ellipses);
                output.Plate.Add(output.Lines);
                output.Plate.Add(output.Rectangles);
                output.Plates.Add(output.Plate);
            }
            #endregion

            output.TotalPlateNum = Test.sheetNum;
            output.PatternNum = Test.patternNum;
            output.UtilizationRate = Test.rate;
            lock (_outputs)
            {
                _outputs.Add(output);
            }
        }

        void PrintStripe(int[] s,ref double x,ref double y, ref List<int[]> ellipses, ref List<int[]> lines)
        {
            /*
             * 毛坯id：   s[0] 
             * 毛坯排数:  s[1] 
             * 条带方向： s[2] 
             * 条带长度： s[3] 
             * 毛坯个数： s[4]
             */

            //x方向
            if (s[2] == 0)
            {
                int k;
                int d = s[2] + 1;//方向
                int _num; //每一排数量不同时的修正
                int diameter = Constant.diameter[s[0]];//直径

                //一条条带中的排                        
                for (k = 0; k < s[1] + 1; k++)
                {
                    int num = s[4] / (s[1] + 1);//数量
                    if (k % 2 == 0 && s[4] % (s[1] + 1) != 0)
                    {
                        _num = 1;
                    }
                    else
                    {
                        _num = 0;
                    }
                    num += _num;
                    //更新排坐标
                    double x_temp = x + (k % 2) * diameter / 2;
                    double y_temp = y + k * (1.732 * diameter / 2);
                    //输出
                    int[] ell = new int[] { 2, (int)x_temp, (int)y_temp, diameter, diameter, d, num };
                    ellipses.Add(ell);

                }
                //更新矩形坐标，x不变
                y += Constant.diameter[s[0]] + (k - 1) * (1.732 * diameter / 2);
                int[] line = new int[] { 3, (int)x, (int)y, Constant.sheetLength, (int)y, 1, 1 };
                lines.Add(line);
            }
            //y方向
            else if(s[2] == 1)
            {
                int k = 0;
                int d = s[2] + 1;//方向 
                int _num; //每一排数量不同时的修正
                int diameter = Constant.diameter[s[0]];//直径

                //一条条带中的排
                for (k = 0; k < s[1] + 1; k++)
                {
                    int num = s[4] / (s[1] + 1);//数量

                    if (k % 2 == 0 && s[4] % (s[1] + 1) != 0)
                    {
                        _num = 1;
                    }
                    else
                    {
                        _num = 0;
                    }
                    num += _num;
                    //更新排坐标
                    double y_temp = y + (k % 2) * diameter / 2;
                    double x_temp = x + k * (1.732 * diameter / 2);
                    //输出
                    int[] ell = new int[] { 2, (int)x_temp, (int)y_temp, diameter, diameter, d, num };
                    ellipses.Add(ell);

                }
                //更新矩形坐标，y不变
                x += Constant.diameter[s[0]] + (k - 1) * (1.732 * diameter / 2);
                int[] line = new int[] { 3, (int)x, (int)y, (int)x, Constant.sheetWidth, 2, 1 };
                lines.Add(line);
            }
            else if (s[2] == 2)
            {
                x = Constant.sheetLength;
                y = 0;
                int k = 0;
                int d = s[2] ;//方向 
                int diameter = Constant.diameter[s[0]];//直径

                //一条条带中的排
                for (k = 0; k < s[1] + 1; k++)
                {
                    int num = s[4] / (s[1] + 1);//数量

                    //更新排坐标
                    double y_temp = y ;
                    double x_temp = x - (k+1) *  diameter ;
                    //输出
                    int[] ell = new int[] { 2, (int)x_temp, (int)y_temp, diameter, diameter, d, num };
                    ellipses.Add(ell);
                    lines.Add(new int[] { 3, (int)x_temp, (int)y_temp, (int)x_temp, Constant.sheetWidth, 2, 1 });
                }
                //排样下的说明
              var  offcutW= (s[1] + 1) * diameter;
                output.PlateRemark[output.PlateRemark.Count - 1] = $"毛坯直径：{diameter},毛坯号：{s[0]+1}";
                Constant.sheetLength = Constant.sheetLength - (s[1] + 1) * diameter;
                x = 0;
            }
        }
    }
}
